#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <mysql/mysql.h>
#include <sstream>
#include <cstring>
#include <iomanip>
#include <jsoncpp/json/json.h>

#include "../comm/log.hpp"
#include "../comm/util.hpp"
#include "../comm/mysql_connection_pool/ConnectionPool.hpp"

namespace ns_model
{
    using namespace ns_util;
    using namespace ns_log;

    // 小说
    struct book
    {
        std::string _book_id;           // 小说id值 -- 唯一标识
        std::string _book_type;         // 小说类型
        std::string _book_status;       // 小说状态
        std::string _book_title;        // 小说名
        std::string _book_author;       // 小说作者
        std::string _book_introduction; // 小说简介
        std::string _total_words;       // 小说总字数
    };

    // 用户
    struct user
    {
        std::string _user_id;       // 用户id
        std::string _user_name;     // 用户名
        std::string _user_email;    // 用户邮箱
        std::string _user_password; // 用户密码
    };

    // mysql登录参数
    const std::string host = "127.0.0.1";
    const std::string user = "novel_web_client";
    const std::string passwd = "yy20040706";
    const std::string db = "novel_web";
    const int port = 3306;

    // 类别pair（主要用于首页分类作品）
    const std::vector<std::pair<std::string, std::string>> twoTypes =
        {
            {"玄幻", "奇幻"},
            {"科幻", "悬疑"},
            {"武侠", "仙侠"},
            {"都市", "现实"},
            {"历史", "军事"},
            {"游戏", "体育"},
            {"轻小说", ""},
            {"诸天无限", ""}};

    class model
    {
    public:
        model()
        {
        }
        ~model()
        {
        }

    public:
        // 数据库中提取书籍信息
        bool queryMysql(const std::string sql, std::vector<book> *out)
        {
            // 获取mysql连接池
            connectionPool *cp = connectionPool::getConnectionPool();
            if (cp == nullptr)
            {
                LOG(FATAL) << "MySQL连接池创建失败"
                           << "\n";
                return false;
            }
            // 获取连接
            std::shared_ptr<connection> conn = cp->getConnection();
            // 执行sql语句
            MYSQL_RES *res = conn->query(sql);

            if (res == nullptr)
            {
                return false;
            }

            book b;
            // 分析结果
            MYSQL_ROW row;

            while (row = mysql_fetch_row(res))
            {

                // std::string _book_id;           // 小说id值 -- 唯一标识
                // std::string _book_type;         // 小说类型
                // std::string _book_status;       // 小说状态
                // std::string _book_title;        // 小说名
                // std::string _book_author;       // 小说作者
                // std::string _book_introduction; // 小说简介
                // std::string _total_words;       // 小说总字数
                b._book_id = row[0];
                b._book_type = row[1];
                b._book_status = row[2];
                b._book_title = row[3];
                b._book_author = row[4];
                b._book_introduction = row[5];
                b._total_words = row[6];
                out->push_back(b);
            }
            mysql_free_result(res);

            return true;
        }

        // 查询用户
        bool searchUser(const std::string &sql, struct user *usr)
        {
            // 获取mysql连接池
            connectionPool *cp = connectionPool::getConnectionPool();
            if (cp == nullptr)
            {
                LOG(FATAL) << "MySQL连接池创建失败"
                           << "\n";
                return false;
            }
            // 获取连接
            std::shared_ptr<connection> conn = cp->getConnection();
            // 执行sql语句
            MYSQL_RES *res = conn->query(sql);

            if (res == nullptr)
            {
                return false;
            }

            MYSQL_ROW row;
            row = mysql_fetch_row(res);
            if (row == nullptr)
            {
                return false;
            }
            usr->_user_id = row[0];
            usr->_user_name = row[1];
            usr->_user_email = row[2];
            usr->_user_password = row[3];

            mysql_free_result(res);
            return true;
        }

        // 获取热门作品（只是写了个逻辑，单纯从数据库中提取书籍，没有涉及到算法，例如识别作品热门程度）
        bool getHotBooks(std::unordered_map<std::string, std::vector<struct book>> *hotBooks)
        {
            bool ret = true;
            for (auto &typePair : twoTypes)
            {
                std::vector<struct book> books;
                std::string sql = "select * from books where book_type = '";
                sql += typePair.first + "' ";
                sql += "or book_type = '";
                sql += typePair.second + "' limit 5 offset 0 ";
                std::string key = typePair.first + typePair.second;
                if (!queryMysql(sql, &books))
                {
                    ret = false;
                    return ret;
                }
                hotBooks->insert(std::make_pair(key, books));
            }
            return ret;
        }

        // 获取新作品
        bool getNewBooks(std::vector<struct book> *newBooks)
        {
            std::string sql = "select * from books order by book_id DESC limit 7 offset 0";
            return queryMysql(sql, newBooks);
        }

        // 获取全部作品页面书籍
        bool getAllBooks(const std::string page, std::vector<book> *out)
        {
            std::stringstream ss;
            ss << "select * from books order by book_id limit 20 offset " << (atoi(page.c_str()) - 1) * 20;
            std::string sql = ss.str();
            return queryMysql(sql, out);
        }

        // 获取不同类别书籍
        bool getTypeOfBooks(const std::string &type, const std::string page, std::vector<book> *out)
        {
            std::string sql = "select * from books where book_type = '";
            std::string book_type = ns_util::stringUtil::getBookType(type);
            sql += book_type;
            sql += "'";
            sql += " order by book_id limit 20 offset ";
            std::stringstream ss;
            ss << (atoi(page.c_str()) - 1) * 20;
            sql += ss.str();
            std::cout << sql << std::endl;
            return queryMysql(sql, out);
        }

        // 登录参数提交
        bool loginSumbit(const std::string &in_json, std::string *out_json)
        {
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string username = in_value["username"].asString();
            std::string password = in_value["password"].asString();

            // std::cout << username << password << std::endl;
            Json::Value out_value;
            bool ret = true;
            std::string sql = "select * from user where user_email = '" + username + "'";
            struct user usr;
            searchUser(sql, &usr);
            if (password == usr._user_password)
            {
                out_value["status"] = 0;
                out_value["reason"] = "登录成功";
                out_value["userid"] = usr._user_id;
            }
            else
            {
                out_value["status"] = 1;
                out_value["reason"] = "账号或密码错误";
                ret = false;
            }
            Json::StyledWriter writer;
            *out_json = writer.write(out_value);
            return ret;
        }

        // 获取用户信息
        bool getUserInfo(const std::string &userid, std::string *html, struct user *usr)
        {
            std::string sql = "select * from user where user_id = " + userid;
            return searchUser(sql, usr);
        }

        // 添加用户sql
        bool insertSql(const std::string &sql)
        {
            // 获取mysql连接池
            connectionPool *cp = connectionPool::getConnectionPool();
            if (cp == nullptr)
            {
                LOG(FATAL) << "MySQL连接池创建失败"
                           << "\n";
                return false;
            }
            // 获取连接
            std::shared_ptr<connection> conn = cp->getConnection();

            if (conn->update(sql))
            {
                return true;
            }

            return false;
        }

        // 添加用户
        bool addUser(const std::string &in_json, std::string *out_json)
        {
            bool ret = true;
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            Json::Value out_value;
            struct user usr;
            std::string useremail = in_value["useremail"].asString();

            std::string sql = "select * from user where user_email = '" + useremail + "'";
            if (searchUser(sql, &usr))
            {
                out_value["status"] = 1;
                out_value["reason"] = "该用户已存在";
                ret = false;
            }
            else
            {
                std::string username = in_value["username"].asString();
                std::string userpassword = in_value["userpassword"].asString();

                std::string sql = "insert into user (user_name, user_email, user_password) values ('";
                sql += username + "', '";
                sql += useremail + "', '";
                sql += userpassword + "')";

                insertSql(sql);

                out_value["status"] = 0;
                out_value["reason"] = "注册成功";
            }

            Json::StyledWriter writer;
            *out_json = writer.write(out_value);
            return ret;
        }

    private:
        std::unordered_map<std::string, book>
            _books; // 小说id : 小说
    };
}